﻿using System;
using System.Runtime.Serialization;
using System.Xml.Linq;
using NCMIS.AccessControl;
using NCMIS.ObjectModel.MetaData;

namespace NCMIS.ObjectModel
{
    /// <summary>
    /// Represents the CMIS Object type.
    /// </summary>
    [DataContract(Name = "object", Namespace = CmisNs.Cmis)]
    public  class CmisObject
    {
        /// <summary>
        /// Uniquely identifies this instance.
        /// </summary>
        [DataMember(Name = "objectId", EmitDefaultValue = false)]
        public string Id
        {
            get;
            set;
        }

        /// <summary>
        /// The property collection of this instance.
        /// </summary>
        [DataMember(Name = "properties", EmitDefaultValue = false)]
        public CmisProperties Properties
        {
            get;
            set;
        }

        /// <summary>
        /// The Allowable Actions for this instance.
        /// </summary>
        [DataMember(Name = "allowableActions", EmitDefaultValue = false)]
        public AllowableActions AllowableActions
        {
            get;
            set;
        }

        /// <summary>
        /// The collection of relationship objects, tied to this instance.
        /// </summary>
        [DataMember(Name = "relationship", EmitDefaultValue = false)]
        public CmisObject[] Relationship
        {
            get;
            set;
        }

        /// <summary>
        /// The change event information for this instance.
        /// </summary>
        [DataMember(Name = "changeEventInfo", EmitDefaultValue = false)]
        public CmisChangeEvent ChangeEventInfo
        {
            get;
            set;
        }

        /// <summary>
        /// The Access Control List for this instance.
        /// </summary>
        [DataMember(Name = "acl", EmitDefaultValue = false)]
        public AccessControlList Acl
        {
            get;
            set;
        }

        [DataMember(Name = "exactACL", EmitDefaultValue = false)]
        public Nullable<bool> ExactAcl
        {
            get;
            set;
        }

        /// <summary>
        /// The policy ids for this document.
        /// </summary>
        [DataMember(Name = "policyIds", EmitDefaultValue = false)]
        public ListOfIds PolicyIds
        {
            get;
            set;
        }

        /// <summary>
        /// The renditions for this object (if this object is a Document object, or a Document object descendant).
        /// </summary>
        [DataMember(Name = "rendition", EmitDefaultValue = false)]
        public Rendition[] Rendition
        {
            get;
            set;
        }

        /// <summary>
        /// Gets a specified <see cref="NCMIS.ObjectModel.CmisProperty"/> instance from the properties collection of the current object.
        /// </summary>
        /// <param name="propertyName">The name of the property to retrieve.</param>
        /// <returns>A <see cref="NCMIS.ObjectModel.CmisProperty"/> or null if no matching property is found.</returns>
        public CmisProperty GetProperty(string propertyName)
        {
            CmisProperty cmisProperty = null;
            if (this.Properties != null)
            {
                for (int i = 0; i < this.Properties.Items.Length; i++)
                {
                    if (this.Properties.Items[i].PropertyDefinitionId.Equals(propertyName))
                    {
                        cmisProperty = this.Properties.Items[i];
                        break;
                    }
                }
            }
            return cmisProperty;
        }

        /// <summary>
        /// Returns a <see cref="System.Xml.Linq.XElement"/> RestAtom representation of this instance.
        /// </summary>
        /// <returns>A <see cref="System.Xml.Linq.XElement"/> object representation.</returns>
        public XElement ToXElement()
        {
            XNamespace nsCore = CmisNs.Cmis;
            XNamespace nsRa = CmisNs.Cmisra;

            XElement @object = new XElement(nsRa + "object");
            @object.Add(new XElement(nsCore + "objectId", this.Id));
            @object.Add(new XElement(nsCore + "properties"));
            XElement properties = @object.Element(nsCore + "properties");
            foreach (CmisProperty cmisProperty in this.Properties.Items)
            {
                properties.Add(cmisProperty.ToXElement());
            }
            //
            // ACL
            //
            if (this.Acl != null)
            {
                XElement acl = new XElement(nsCore + "acl");
                foreach (AccessControlEntry ace in this.Acl.Permissions)
                {
                    XElement permissionAce = new XElement(nsCore + "permission",
                        new XElement(nsCore + "principal",
                            new XElement(nsCore + "principalId", ace.Principal.PrincipalId)));
                     foreach (string permission in ace.Permissions)
                    {
                        XElement permissionString = new XElement(nsCore + "permission", permission);
                        permissionAce.Add(permissionString);
                    }
                    permissionAce.Add(new XElement(nsCore + "direct", ace.Direct.ToString().ToLower()));
                    acl.Add(permissionAce);
                }
                @object.Add(acl);
            }

            return @object;
        }
    }
}
